//Copyright (C) 2013 Julio Espindola
//
//This file is part of VSize Checkers.
//
//VSize Checkers is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//VSize Checkers is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with VSize Checkers.  If not, see <http://www.gnu.org/licenses/>.

package checkers;

import java.util.ArrayList;

public class Checkers implements java.io.Serializable
{
    public static final int EMPTY = -1;
    public static final int WHITE_PAWN = 0;
    public static final int BLACK_PAWN = 1;
    public static final int WHITE_QUEEN = 2;
    public static final int BLACK_QUEEN = 3; 
    public static final int WHITE = 0;
    public static final int BLACK = 1; 
    public static final int WHITE_WIN = 1;
    public static final int BLACK_WIN = 2;
    public static final int DRAW = 3;
    
    private Board board;
    public int size;
    public int squaresNum;
    public int currentMove;
    public ArrayList<Move> validMoves;
    public ArrayList<Move> movesPlayed;
    
    public Checkers(int size)
    {
        board = new Board(size);
        this.size = size;
        squaresNum = board.squares.length-1;
        currentMove = 0;
        validMoves = board.findMoves();
        movesPlayed = new ArrayList<Move>();
    }
    
    public void updateStatus()
    {
        board.squares[0] &= Board.TURN;
        board.halfMove = 0;
        board.countPieces();
        validMoves = board.findMoves();
        board.checkForWin(validMoves);
        resetHashTable();
    }
    
    public void resetHashTable()
    {
        Ai.table.resetTable();
        board.initZobrist();
        board.hashBoard();
    }
    
    public Move getLastMove()
    {
        return movesPlayed.get(currentMove-1);
    }
    
    public int getSquare(int square)
    {
        if(board.isFree(square))
            return -1;
        else
            return (board.getPiece(square)>>2);
    }
    
    public boolean whiteToPlay()
    {
        return board.getTurn();
    }
    
    public void getValidMoves()
    {
        validMoves = new Board(board).findMoves();
    }
    
    public ArrayList<Move> getPlayerMove(int start, int dest)
    {
        ArrayList<Move> moves = new ArrayList<Move>();
        
        for(int i=0; i<validMoves.size(); ++i)
        {
            Move m = validMoves.get(i);
            if(start == m.start && dest == m.dest)
                moves.add(m);
        }
        
        return moves; 
    }
    
    public Move getBestMoveAI(int depth)
    {
        if(validMoves.size()==1) return validMoves.get(0);
        else return Ai.getBestMove(new Board(board), validMoves, depth);
    }
    
    public int getStatus()
    {
        return board.getStatus();
    }
    
    public void switchTurn()
    {
        board.squares[0] ^= Board.TURN;
    }
    
    public void setAiLimit(int lim)
    {
        Ai.limit = lim;
    }
    
    public void setSquare(int square, int piece)
    {
        byte p = piece==-1 ? 0: (byte)((piece<<2)|Piece.PIECE);
        board.setPiece(square, p);
    }
    
    public int play(Move move)
    {
        if(currentMove < movesPlayed.size())
            movesPlayed.subList(currentMove, movesPlayed.size()).clear();
        validMoves = board.makeMove(move);
        movesPlayed.add(move);
        ++currentMove;
        return board.getStatus();
    }
    
    public void undoLastMove()
    {
        if(movesPlayed.isEmpty()) return;
        int last = movesPlayed.size()-1;
        board.undoMove(movesPlayed.get(last));
        movesPlayed.remove(last);
        validMoves = new Board(board).findMoves();
    }
    
    public void previousMove()
    {
        if(currentMove == 0) return;
        board.undoMove(movesPlayed.get(--currentMove));
        validMoves = new Board(board).findMoves();
    }
    
    public void nextMove()
    {
        if(currentMove == movesPlayed.size()) return;
        board.makeMove(movesPlayed.get(currentMove++));
        validMoves = new Board(board).findMoves();
    }
    
    @Override
    public String toString()
    {
        boolean unused = true;
        String s = "\n";
        
        for(int i=0; i<validMoves.size(); ++i)
            s += validMoves.get(i) + "\n";
        
        s += "\n";
        int lim = (size*size)/2;
        for(int i=1; i<=lim; ++i)
        {
            if(unused) s += "- ";
            switch(getSquare(i))
            {
                case -1: s += "- "; break;
                case 0: s += "o "; break;
                case 1: s += "x "; break;
                case 2: s += "O "; break;
                case 3: s += "X "; break;
            }
            if(!unused) s += "- ";
            
            if(i%(size/2) == 0)
            {
                unused ^= true;
                s += "\n";
            }
        }
        return s;
    }
}
